package com.jubaozan.framework.sentinel.springmvc.init;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.csp.sentinel.cluster.ClusterStateManager;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientAssignConfig;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfig;
import com.alibaba.csp.sentinel.cluster.client.config.ClusterClientConfigManager;
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterFlowRuleManager;
import com.alibaba.csp.sentinel.cluster.flow.rule.ClusterParamFlowRuleManager;
import com.alibaba.csp.sentinel.cluster.server.config.ClusterServerConfigManager;
import com.alibaba.csp.sentinel.cluster.server.config.ServerTransportConfig;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.redis.RedisDataSource;
import com.alibaba.csp.sentinel.datasource.redis.config.RedisConnectionConfig;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.property.PropertyListener;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.alibaba.csp.sentinel.util.AppNameUtil;
import com.alibaba.csp.sentinel.util.HostNameUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.jubaozan.framework.sentinel.constant.RuleKeyConstant;
import com.jubaozan.framework.sentinel.listener.RedisRulePublisher;
import com.jubaozan.framework.sentinel.springmvc.cluster.entity.ClusterGroupEntity;
import com.jubaozan.framework.sentinel.springmvc.constant.ClusterConstants;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import lombok.var;

/**
 * @author jiangjinwu
 * @version 1.0
 * @since 2025/7/17 17:54
 */

@Slf4j
public class RedisDegradeDatasourceInitFunc implements InitFunc {

    private static final String APP_NAME = AppNameUtil.getAppName();

    private final String remoteAddress = "localhost:8848";
    private final String groupId = "SENTINEL_GROUP";

    private final String flowDataId = APP_NAME + ClusterConstants.FLOW_POSTFIX;
    private final String paramDataId = APP_NAME + ClusterConstants.PARAM_FLOW_POSTFIX;
    private final String configDataId = APP_NAME + "-cluster-client-config";
    private final String clusterMapDataId = APP_NAME + ClusterConstants.CLUSTER_MAP_POSTFIX;
    RedisRulePublisher redisRulePublisher;
    RedisConnectionConfig config;
    RuleKeyConstant ruleKeyConstant;

    @Override
    public void init() throws Exception {

        redisRulePublisher = SpringUtil.getBean(RedisRulePublisher.class);
        ruleKeyConstant = SpringUtil.getBean(RuleKeyConstant.class);
        var builder = RedisConnectionConfig.builder();
        builder
            .withHost(SpringUtil.getProperty("spring.redis.host"))
            .withPort(Integer.parseInt(SpringUtil.getProperty("spring.redis.port")))
            .withPassword(SpringUtil.getProperty("spring.redis.password"));

        if (StringUtil.isNotEmpty("spring.redis.database")) {
            builder.withDatabase(Integer.parseInt(SpringUtil.getProperty("spring.redis.database")));
        }

        if (StringUtil.isNotEmpty(SpringUtil.getProperty("spring.redis.timeout"))) {
            builder.withTimeout(Long.parseLong(SpringUtil.getProperty("spring.redis.timeout")));
        }
        config = builder.build();

        // Register client dynamic rule data source.
        initDynamicRuleProperty();


    }

    private void initDynamicRuleProperty() {
        ReadableDataSource<String, List<DegradeRule>> paramRuleSource = new RedisDataSource<List<DegradeRule>>(config, groupId,
            paramDataId, source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {
        }));

        DegradeRuleManager.register2Property(paramRuleSource.getProperty());

    }


    private boolean machineEqual(/*@Valid*/ ClusterGroupEntity group) {
        return getCurrentMachineId().equals(group.getMachineId());
    }

    private String getCurrentMachineId() {
        // Note: this may not work well for container-based env.
        return HostNameUtil.getIp() + SEPARATOR + TransportConfig.getRuntimePort();
    }

    private static final String SEPARATOR = "@";
}
